package com.ymttest.common.order.userquery;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;
import org.joda.time.Period;
import org.springframework.util.CollectionUtils;

import com.google.common.collect.Lists;
import com.shop2cn.iapi.sqsynctrade.paremeter.mongo.details.Delivery;
import com.shop2cn.iapi.sqsynctrade.paremeter.mongo.details.Fund;
import com.shop2cn.iapi.sqsynctrade.paremeter.mongo.details.Product;
import com.shop2cn.iapi.sqsynctrade.paremeter.mongo.details.Refund;
import com.ymatou.iapi.synctrade.parameter.mongo.Order;
import com.ymatou.iapi.trading.ordersync.parameter.ProductPromotion;
import com.ymatou.iapi.trading.userquery.parameter.resp.ConsultingOrderInfo;
import com.ymatou.iapi.trading.userquery.parameter.resp.OrderItemInfoForConsult;
import com.ymttest.common.enums.LogisticsTypeEnum;
import com.ymttest.common.enums.OrderOperationNoticeEnum;
import com.ymttest.common.enums.OrderOperationTypeEnum;
import com.ymttest.common.enums.OrderStatusEnum;
import com.ymttest.common.enums.SalesRefundStatusEnum;
import com.ymttest.common.enums.SalesTypeStringEnum;
import com.ymttest.common.order.constants.Constants;
import com.ymttest.common.order.userquery.client.LogisticsClient;
import com.ymttest.common.order.userquery.model.vo.BargainGroupInfo;
import com.ymttest.common.order.userquery.model.vo.OrderConsigneeInfo;
import com.ymttest.common.order.userquery.model.vo.OrderConsumerInfo;
import com.ymttest.common.order.userquery.model.vo.OrderInfo;
import com.ymttest.common.order.userquery.model.vo.OrderOperationInfo;
import com.ymttest.common.order.userquery.model.vo.PaymentDetail;
import com.ymttest.common.order.userquery.model.vo.PaymentDetailItem;
import com.ymttest.common.order.userquery.model.vo.PaymentInfo;
import com.ymttest.common.order.userquery.model.vo.ProductInfo;
import com.ymttest.common.order.userquery.model.vo.SellerInfo;
import com.ymttest.common.order.userquery.model.vo.StatusInfo;
import com.ymttest.common.order.userquery.model.vo.TransferInfo;
import com.ymttest.common.order.userquery.util.OrderHelper;
import com.ymttest.common.order.userquery.util.Utils;
import com.ymttest.utils.DataUtil;
import com.ymttest.utils.YMTDateUtil;

/**
 * @author luoshiqian 2016/12/28 16:39
 */
public class OrderInfoBuilder {

	private final static String TIME_STRING = YMTDateUtil.YMDTHMSS_STRING;

	public static LogisticsClient logisticsClient;
	public static final BigDecimal ONE_HOUR_SECONDS = new BigDecimal(3600);
	private static final int BARGAIN_GROUP = 1; // 1：砍价团

	public static OrderInfo convertFromOrder(Order o, boolean isSearchDemositic) {
		OrderInfo orderInfo = new OrderInfo();
		orderInfo.setOrderId(o.getId());
		orderInfo.setOrderGroupId(o.getMainOrderId());
		orderInfo.setAddTime(o.getAddTime());
		orderInfo.setAutoCancelOrderHours(o.getAutoCancelHour());
		orderInfo.setCancelReason(o.getReason());
		orderInfo.setPlatform(OrderHelper
				.getPlatformEnumInfo(o.getPlatSource()).getValue());

		orderInfo.setPreSaleOrder(o.isPreSale());
		orderInfo.setDomesticDelivered(o.isLocalDelivery());

		// 订单状态信息
		StatusInfo statusInfo = new StatusInfo();
		statusInfo.setOrderStatus(o.getTradingStatus());

		// 砍价团信息
		if (o.getBizType() != null && o.getBizType().equals(BARGAIN_GROUP)) {
			BargainGroupInfo bargainGroup = new BargainGroupInfo();
			bargainGroup.setBizId(o.getBizId());
			bargainGroup.setBizStatus(o.getBizStatus());
			bargainGroup.setBizSubType(o.getBizSubType());

			orderInfo.setBargainGroup(bargainGroup);
		}

		List<Refund> refundList = o.getRefunds();
		if (!DataUtil.isNullOrEmpty(refundList)) {
			refundList
					.stream()
					.forEach(
							r -> {
								if (r.getRefundStatus() != null
										&& r.getRefundStatus() == SalesRefundStatusEnum.Processing
												.getValue()) {
									statusInfo
											.setSalesRefundStatus(SalesRefundStatusEnum.Processing
													.getValue());
									return; // xxx 存在了处理中 直接break出去
								}
								// 如果存在成功的，则退款成功（如果存在成功 也存在处理中，则是处理中）
								if (r.getRefundStatus() != null
										&& r.getRefundStatus() == SalesRefundStatusEnum.Success
												.getValue()) {
									statusInfo
											.setSalesRefundStatus(SalesRefundStatusEnum.Success
													.getValue());
								}
							});
		}
		orderInfo.setStatus(statusInfo);

		// 卖家信息
		SellerInfo sellerInfo = new SellerInfo(o.getSellerId(), o.getContent(),
				o.getSellerLogin());
		orderInfo.setSeller(sellerInfo);

		// 收货人信息
		OrderConsigneeInfo consigneeInfo = new OrderConsigneeInfo(
				o.getReceiver(),
				com.ymatou.iapi.optrade.parameter.utill.Utils.decryptAES(o
						.getUaddress()), o.getPostCode(),
				com.ymatou.iapi.optrade.parameter.utill.Utils.decryptAES(o
						.getUphone()),
				com.ymatou.iapi.optrade.parameter.utill.Utils.decryptAES(o
						.getUphone()));
		orderInfo.setConsignee(consigneeInfo);

		// 买家信息
		boolean isUploadedIdCard = o.isUploadedIdCard();

		OrderConsumerInfo consumerInfo = new OrderConsumerInfo(o.getUserId(),
				o.isNeedUploadIdCard(), isUploadedIdCard, o.getComment());
		orderInfo.setConsumer(consumerInfo);

		// 构建支付信息
		PaymentInfo paymentInfo = buildPaymentInfo(o);
		orderInfo.setPayment(paymentInfo);

		// 收货、退货信息
		TransferInfo transferInfo = new TransferInfo();
		Delivery delivery = o.getDelivery();
		if (null != delivery) {
			transferInfo
					.setAutoReceiveTime((!delivery.isPause() && delivery
							.getFrozenTime() != null) ? delivery
							.getFrozenTime() : null);
			if (delivery.getDelayUserId() != null) {
				transferInfo.setIsDelayAutoReceiveTime(delivery
						.getDelayUserId().equals(o.getUserId()));
			}
		}

		transferInfo.setLocalRefundApplyTime(null);
		transferInfo.setSupportLocalRefund(true); // 已不使用 ，默认为true 兼容.net
		transferInfo.setReceiptConfirmedTime(o.getReceiveTime());
		orderInfo.setTransfer(transferInfo);

		// 商品信息
		orderInfo.setProducts(buildProductInfo(o));

		// 订单允许操作信息
		orderInfo.setOperation(buildOrderOperationInfo(o, isSearchDemositic));

		return orderInfo;
	}

	/**
	 * 构建支付信息
	 * 
	 * @param o
	 * @return
	 */
	private static PaymentInfo buildPaymentInfo(Order o) {
		Fund fund = o.getFund();
		PaymentInfo paymentInfo = new PaymentInfo();
		paymentInfo.setOnlyNeedPayOnce(true);
		paymentInfo.setCouponValue(o.getYmtCouponAmount());
		paymentInfo.setCouponCode(o.getYmtCouponCode());
		paymentInfo.setSellerCouponCode(o.getSellerCouponCode());
		paymentInfo.setSellerCouponAmount(o.getSellerCouponAmount());
		paymentInfo.setEarnest(DataUtil.BigDecimall.GetValueOrDefault(
				o.getTotalPrice()).add(
				DataUtil.BigDecimall.GetValueOrDefault(o.getPreDiscount())));
		paymentInfo.setFirstPay(OrderHelper.getPrePaidAmount(o));
		paymentInfo.setRealPay(OrderHelper.getAmountOfRealPay(o));

		paymentInfo.setFreight(o.getFreight());
		String lpt = YMTDateUtil.getBeforeOrNextHour(YMTDateUtil.getFormatTime(
				o.getAddTime(), TIME_STRING), DataUtil.BigDecimall
				.GetValueOrDefault(o.getAutoCancelHour()).intValue(),
				TIME_STRING);
		paymentInfo.setLastPayTime(YMTDateUtil.parseDate(lpt, TIME_STRING));
		paymentInfo.setPaidInFull(true);
		paymentInfo.setTotalPrice(o.getTotalPrice());

		paymentInfo.setTradingId(o.getTradingId() == null ? 0 : o
				.getTradingId());

		if (fund != null) {
			paymentInfo.setRealPostPay(OrderHelper.getPostPaidAmount(fund));
			paymentInfo.setUseGiftAmount(OrderHelper.getAmountOfGift(fund));
			paymentInfo.setPostPaidAmountOfGift(fund.getPostGif());
			paymentInfo.setGiftUsedAmountOfPostpay(fund.getPostGif());
		}

		paymentInfo.setTotalPriceChange(o.getPreDiscount());
		paymentInfo.setExpectedPayAmount(o.getTotalPrice());
		if (!DataUtil.isNullOrEmpty(o.getRefunds())) {
			paymentInfo.setSalesRefundAmount(o
					.getRefunds()
					.stream()
					.filter(e -> e.getRefundStatus().equals(
							SalesRefundStatusEnum.Success.getValue()))
					.map(e -> DataUtil.BigDecimall.GetValueOrDefault(e
							.getRefundAmount())).reduce(BigDecimal::add)
					.orElse(BigDecimal.ZERO));
		}
		paymentInfo.setExpectedPostpayAmount(BigDecimal.ZERO);
		paymentInfo.setPromotionReducedAmount(o.getSellerPromotionAmount());

		if (DataUtil.BigDecimall.compare(paymentInfo.getFirstPay(),
				BigDecimal.ZERO) > 0 && fund != null) {
			PaymentDetail paymentDetail = new PaymentDetail();
			if (DataUtil.BigDecimall.compare(fund.getPaidCash(),
					BigDecimal.ZERO) > 0) {
				PaymentDetailItem earnest = new PaymentDetailItem();
				if (StringUtils.isNotBlank(o.getPayChannel())) {
					earnest.setThirdPartyName(o.getPayChannel()
							.equals("Weixin") ? "wechat" : o.getPayChannel()
							.toLowerCase());
				}
				earnest.setThirdParty(fund.getPaid3P());
				earnest.setAccount(DataUtil.BigDecimall
						.GetValueOrDefault(fund.getPaidCash())
						.subtract(
								DataUtil.BigDecimall.GetValueOrDefault(fund
										.getPaid3P()))
						.subtract(
								DataUtil.BigDecimall.GetValueOrDefault(fund
										.getPrepaidCard())));
				earnest.setGift(fund.getPaidGif());
				earnest.setCoupon(fund.getYmtCoupon());
				earnest.setSellerCoupon(fund.getSellerCoupon());
				earnest.setFreeCard(fund.getPaidFreeCard());
				paymentDetail.setEarnest(earnest);
			}

			if (DataUtil.BigDecimall.compare(fund.getPostCash(),
					BigDecimal.ZERO) > 0) {
				PaymentDetailItem postpay = new PaymentDetailItem();
				postpay.setThirdParty(BigDecimal.ZERO);
				postpay.setAccount(DataUtil.BigDecimall.GetValueOrDefault(fund
						.getPostCash()));
				postpay.setGift(fund.getPostGif());
				paymentDetail.setPostpay(postpay);
			}
			paymentInfo.setDetail(paymentDetail);
		}

		return paymentInfo;
	}

	/**
	 * 商品信息
	 * 
	 * @param order
	 * @return
	 */
	private static List<ProductInfo> buildProductInfo(Order order) {
		List<Product> productList = order.getProducts();
		if (DataUtil.isNullOrEmpty(productList)) {
			return null;
		}
		List<ProductInfo> productInfoList = new ArrayList<ProductInfo>();
		productList
				.forEach(product -> {
					ProductInfo productInfo = new ProductInfo();
					productInfo.setBondedArea(DataUtil.Integerr
							.GetValueOrDefault(product.getBondedArea()));
					productInfo.setCatalogId(product.getCataId());
					productInfo.setIsActivityProduct(product.getActId() != null
							&& product.getActId() > 0);
					productInfo.setCatalogInfo(product.getPropertyInfo());
					
					if (OrderHelper.isShenqiOrder(order)) {
						productInfo.setLogisticsType(order
								.getShenqiLogisticsType());
					} else {
						Integer deliveryType = product.getDeliveryType();
						if (null != deliveryType) {
							LogisticsTypeEnum logisticsTypeEnum = LogisticsTypeEnum
									.forValue(deliveryType);
							productInfo
									.setDeliveryFromBonded(logisticsTypeEnum == LogisticsTypeEnum.BondedDelivery
											|| logisticsTypeEnum == LogisticsTypeEnum.XloboBondedDelivery);
							productInfo.setLogisticsType(deliveryType);
						}
					}

					productInfo.setPriceType(DataUtil.Integerr
							.GetValueOrDefault(product.getPriceType()));
					productInfo.setProductDescription(product.getTitle());
					productInfo.setProductId(product.getProductId());
					productInfo.setProductPicUrl(product.getPicUrl());
					productInfo.setProductsNum(DataUtil.Integerr
							.GetValueOrDefault(product.getPrdCount()));
					productInfo.setProductOriginalPrice(product
							.getPrdOriginalPrice());
					productInfo.setProductSoldPrice(product.getPrdPrice());
					productInfo.setTariffType(product.getTariffType());
					productInfo.setProductRefundChannel(DataUtil.Integerr
							.GetValueOrDefault(product.getRefundChannel()));
					productInfo.setProductRefund(product.getPrdRefundStatus() != null
							&& product.getPrdRefundStatus() != 0);
					productInfo.setPackageNo(product.getPackageNo());

					productInfo.setSalesType(SalesTypeStringEnum.forValue(
							product.getSalesType()).toString());
					productInfo.setSalesRefundCode(product.getPrdRefundNo());
					productInfo.setSalesRefundStatus(product
							.getPrdRefundStatus());
					productInfo.setPreSale(product.getPrdPreSale());
					productInfo.setThirdPartyDiscount(DataUtil.BigDecimall
							.GetValueOrDefault(product.getPrdDiscount3P()));
					productInfo.setSupportRtnWithoutReason(product
							.getReturn7d());
					productInfo.setFreightFree(product.isFreightFree());

					productInfo.setCouponAmount(product.getPrdYmtCoupon());
					productInfo.setSellerCouponAmount(product
							.getPrdSellerCoupon());
					productInfo.setProductVer(product.getProductVersion());
					productInfo.setPspProduct(product.isPspProduct());

					productInfoList.add(productInfo);
				});

		return productInfoList;
	}

	/**
	 * 订单当前状态下的可操作信息. null表示不能进行操作
	 * 
	 * @param order
	 * @return
	 */
	@SuppressWarnings("incomplete-switch")
	private static OrderOperationInfo buildOrderOperationInfo(Order order,
			boolean isSearchDemositic) {
		
		int tradingStatus = order.getTradingStatus();

		OrderStatusEnum statusEnum = OrderStatusEnum
				.forValue(tradingStatus);

		if (statusEnum == null) {
			return null;
		}
		
		// 虚拟物流的商品 接单后不允许买家操作
		if (!CollectionUtils.isEmpty(order.getProducts())
				&& order.getProducts().get(0).getDeliveryType() == LogisticsTypeEnum.AutoDelivery
						.getValue()
				&& (statusEnum == OrderStatusEnum.SellerAccept
						|| statusEnum == OrderStatusEnum.Shipped || statusEnum == OrderStatusEnum.Received)) {
			return null;
		}

		switch (statusEnum) {
		case OrderEstablish:
			return waitingForConsumerPay();
		case AccountPaid:
			return waitingForSellerTakeOrder(order);
		case SellerAccept:
			return waitingForDelivery(order);
		case Shipped:
			return waitingForConsumerConfirmReceived(order, isSearchDemositic);
		case Received:
			return turnover(order);
		}
		
		return null;
	}

	/**
	 * 待支付 订单操作
	 * 
	 * @return
	 */
	private static OrderOperationInfo waitingForConsumerPay() {
		OrderOperationInfo opt = new OrderOperationInfo();
		opt.setType(OrderOperationTypeEnum.Cancel.getValue());
		opt.setActive(true);
		opt.setNeedReason(true);
		return opt;
	}

	/**
	 * 待接单
	 * 
	 * @param o
	 * @return
	 */
	private static OrderOperationInfo waitingForSellerTakeOrder(Order o) {
		if (o.getPaidTime() == null) {
			return null;
		}
		OrderOperationInfo opt = new OrderOperationInfo();
		opt.setType(OrderOperationTypeEnum.Cancel.getValue());

		Period period = new Period(new DateTime(o.getPaidTime()),
				DateTime.now());

		if (Utils.isLonger(period, Constants.TakeOrder)) {
			opt.setActive(true);
			opt.setNeedReason(true);
		} else {
			opt.setActive(false);
			opt.setInterval(Utils
					.convertDotNetTimeSpanPeriod(Constants.TakeOrder));
			opt.setRest(Utils.convertDotNetTimeSpanPeriod(DateTime.now(),
					new DateTime(o.getPaidTime()).plus(Constants.TakeOrder)));
			opt.setNotice(OrderOperationNoticeEnum.UnAcceptOrder.getValue());
		}
		return opt;
	}

	/**
	 * 待发货
	 * 
	 * @param o
	 * @return
	 */
	private static OrderOperationInfo waitingForDelivery(Order o) {
		if (o.getAcceptTime() == null) {
			return null;
		}
		OrderOperationInfo opt = new OrderOperationInfo();

		opt.setType(OrderOperationTypeEnum.SalesRefund.getValue());

		Period period = new Period(new DateTime(o.getAcceptTime()),
				DateTime.now());

		if (Utils.isLonger(period, Constants.Deliver)) {
			opt.setActive(true);
		} else {
			opt.setActive(false);
			opt.setInterval(Utils
					.convertDotNetTimeSpanPeriod(Constants.Deliver));
			opt.setRest(Utils.convertDotNetTimeSpanPeriod(DateTime.now(),
					new DateTime(o.getAcceptTime()).plus(Constants.Deliver)));
			opt.setNotice(OrderOperationNoticeEnum.UnShipped.getValue());
		}

		return opt;
	}

	/**
	 * 待确认收货
	 * 
	 * @param o
	 * @return
	 */
	private static OrderOperationInfo waitingForConsumerConfirmReceived(
			Order o, boolean isSearchDemositic) {
		if (o.getDeliveryTime() == null) {
			return null;
		}
		OrderOperationInfo opt = new OrderOperationInfo();
		opt.setType(OrderOperationTypeEnum.SalesRefund.getValue());

		Period period = new Period(new DateTime(o.getDeliveryTime()),
				DateTime.now());

		if (Utils.isLonger(period, Constants.ConfirmReceived)) {
			opt.setActive(true);
		} else {
			if (logisticsClient == null) {
				logisticsClient = new LogisticsClient();
			}
			boolean isDemosticSigned = false;
			if (isSearchDemositic) {
				isDemosticSigned = logisticsClient.checkDemosticSigned(
						o.getId(), o.getUserId());
			}
			if (isDemosticSigned) {
				opt.setActive(true);
			} else {
				opt.setActive(false);
				opt.setInterval(Utils
						.convertDotNetTimeSpanPeriod(Constants.ConfirmReceived));
				opt.setRest(Utils.convertDotNetTimeSpanPeriod(DateTime.now(),
						new DateTime(o.getDeliveryTime())
								.plus(Constants.ConfirmReceived)));
				opt.setNotice(OrderOperationNoticeEnum.Shipped.getValue());
			}
		}
		return opt;
	}

	/**
	 * 已成交
	 * 
	 * @param o
	 * @return
	 */
	private static OrderOperationInfo turnover(Order o) {
		if (o.getReceiveTime() == null) {
			return null;
		}
		OrderOperationInfo opt = new OrderOperationInfo();
		opt.setType(OrderOperationTypeEnum.ApplyForAfterSales.getValue());

		Period period = new Period(new DateTime(o.getReceiveTime()),
				DateTime.now());

		if (Utils.isLonger(Constants.Turnover, period)) {
			opt.setActive(true);
		} else {
			opt.setActive(false);
			opt.setInterval(Utils
					.convertDotNetTimeSpanPeriod(Constants.Turnover));
			opt.setRest(Utils.convertDotNetTimeSpanPeriod(DateTime.now(),
					new DateTime(o.getReceiveTime()).plus(Constants.Turnover)));
			opt.setNotice(OrderOperationNoticeEnum.Received.getValue());
		}
		return opt;
	}

	public static ProductPromotion convertFromProduct(Product product) {
		if (product.getPromotionId() != null && product.getPromotionId() > 0) {
			ProductPromotion productPromotion = new ProductPromotion();
			productPromotion.setCondition(product.getPromotionCondition());
			productPromotion.setId(product.getPromotionId());
			productPromotion.setName(product.getPromotionName());
			productPromotion.setReducedAmount(product.getPromotionAmount());
			productPromotion.setType(product.getPromotionType());
			productPromotion.setContent(product.getPromotionContent());
			productPromotion.setPartialReducedAmount(product
					.getPrdPromotionAmount());
			return productPromotion;
		}
		return null;
	}

	// 获取待咨询订单信息
	public static ConsultingOrderInfo buildConsultingOrderInfo(Order o) {

		ConsultingOrderInfo oi = new ConsultingOrderInfo();
		oi.setOrderId(o.getId());
		oi.setOrderStatus(o.getTradingStatus());
		oi.setOrderGroupId(o.getMainOrderId());
		oi.setYmtCouponAmount(Utils.zeroIfNull(o.getYmtCouponAmount()));
		oi.setSellerCouponAmount(Utils.zeroIfNull(o.getSellerCouponAmount()));
		oi.setPayableAmount(Utils.zeroIfNull(o.getTotalPrice())
                .add(Utils.zeroIfNull(o.getPreDiscount()))
                .add(Utils.zeroIfNull(o.getFreight()))
                .subtract(Utils.zeroIfNull(o.getYmtCouponAmount()))
                .subtract(Utils.zeroIfNull(o.getSellerCouponAmount()))
                .subtract(Utils.zeroIfNull(o.getYmtPromotionAmount()))
                .subtract(Utils.zeroIfNull(o.getSellerPromotionAmount())));

		List<OrderItemInfoForConsult> itemInfos = Lists.newArrayList();

		o.getProducts()
				.forEach(
						p -> {
							OrderItemInfoForConsult itemInfo = new OrderItemInfoForConsult();
							itemInfo.setProductId(p.getProductId());
							itemInfo.setCatalogId(p.getCataId());
							itemInfo.setPictureUrl(p.getPicUrl());
							itemInfo.setProductCount(p.getPrdCount());
							itemInfo.setPropertyInfo(p.getPropertyInfo());
							itemInfo.setTitle(p.getTitle());
							itemInfo.setProductPrice(p.getPrdPrice());
							itemInfo.setSellerCouponAmount(Utils.zeroIfNull(p
									.getPrdSellerCoupon()));
							itemInfo.setYmtCouponAmount(Utils.zeroIfNull(p
									.getPrdYmtCoupon()));
							itemInfo.setFreightFree(p.isFreightFree());
							itemInfo.setLogisticsType(Utils.zeroIfNull(p
									.getDeliveryType()));
							itemInfo.setOriginalPrice(p.getPrdOriginalPrice());
							itemInfo.setProductRefundChannel(Utils.zeroIfNull(p
									.getRefundChannel()));
							itemInfo.setSalesRefundStatus(p
									.getPrdRefundStatus());
							itemInfo.setPriceType(Utils.zeroIfNull(p
									.getPriceType()));
							itemInfo.setTariffType(Utils.zeroIfNull(p
									.getTariffType()));

							itemInfos.add(itemInfo);
						});

		oi.setOrderItemInfoForConsults(itemInfos);

		return oi;
	}
}
